/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package net.l2emuproject.gameserver.services.mail;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.ScheduledFuture;

import net.l2emuproject.gameserver.datatables.CharNameTable;
import net.l2emuproject.gameserver.entity.itemcontainer.Mail;
import net.l2emuproject.gameserver.system.idfactory.IdFactory;
import net.l2emuproject.gameserver.system.threadmanager.ThreadPoolManager;
import net.l2emuproject.tools.random.Rnd;

/**
 * @author Migi, DS
 */
public final class Message
{
	private static final short	EXPIRATION					= 360;		// 15 days
	private static final byte	COD_EXPIRATION				= 12;		// 12 hours

	private static final int	UNLOAD_ATTACHMENTS_INTERVAL	= 900000;	// 15-30 mins

	// post state
	public static final byte	DELETED						= 0;
	public static final byte	READED						= 1;
	public static final byte	REJECTED					= 2;

	private final int			_messageId, _senderId, _receiverId;
	private final long			_expiration;
	private String				_senderName					= null;
	private String				_receiverName				= null;
	private final String		_subject, _content;
	private boolean				_unread, _fourStars, _news;
	private boolean				_deletedBySender;
	private boolean				_deletedByReceiver;
	private long				_reqAdena;
	private boolean				_hasAttachments;
	private Mail				_attachments				= null;
	private ScheduledFuture<?>	_unloadTask					= null;

	/*
	 * Constructor for restoring from DB.
	 */
	public Message(final ResultSet rset) throws SQLException
	{
		_messageId = rset.getInt("messageId");
		_senderId = rset.getInt("senderId");
		_receiverId = rset.getInt("receiverId");
		_subject = rset.getString("subject");
		_content = rset.getString("content");
		_expiration = rset.getLong("expiration");
		_reqAdena = rset.getLong("reqAdena");
		_hasAttachments = rset.getBoolean("hasAttachments");
		_unread = rset.getBoolean("isUnread");
		_deletedBySender = rset.getBoolean("isDeletedBySender");
		_deletedByReceiver = rset.getBoolean("isDeletedByReceiver");
		_fourStars = rset.getBoolean("isFourStars");
		_news = rset.getBoolean("isNews");
	}

	/*
	 * This constructor used for creating new message.
	 */
	public Message(int senderId, int receiverId, boolean isCod, String subject, String text, long reqAdena)
	{
		_messageId = IdFactory.getInstance().getNextId();
		_senderId = senderId;
		_receiverId = receiverId;
		_subject = subject;
		_content = text;
		if (isCod)
			_expiration = System.currentTimeMillis() + COD_EXPIRATION * 3600000;
		else
			_expiration = System.currentTimeMillis() + EXPIRATION * 3600000;
		_hasAttachments = false;
		_unread = true;
		_deletedBySender = false;
		_deletedByReceiver = false;
		_reqAdena = reqAdena;
	}

	/*
	 * This constructor used for auto-generation of the "return attachments" message
	 */
	public Message(final Message msg)
	{
		_messageId = IdFactory.getInstance().getNextId();
		_senderId = msg.getSenderId();
		_receiverId = msg.getSenderId();
		_subject = "";
		_content = "";
		_expiration = System.currentTimeMillis() + EXPIRATION * 3600000;
		_unread = true;
		_deletedBySender = true;
		_deletedByReceiver = false;
		_fourStars = true;
		_reqAdena = 0;
		_hasAttachments = true;
		_attachments = msg.getAttachments();
		msg.removeAttachments();
		_attachments.setNewMessageId(_messageId);
		_unloadTask = ThreadPoolManager.getInstance().scheduleGeneral(new AttachmentsUnloadTask(this),
				UNLOAD_ATTACHMENTS_INTERVAL + Rnd.get(UNLOAD_ATTACHMENTS_INTERVAL));
	}

	public static final PreparedStatement getStatement(Message msg, Connection con) throws SQLException
	{
		PreparedStatement stmt = con
				.prepareStatement("INSERT INTO messages (messageId, senderId, receiverId, subject, content, expiration, reqAdena, hasAttachments, isUnread, isDeletedBySender, isDeletedByReceiver, isFourStars, isNews) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");

		stmt.setInt(1, msg._messageId);
		stmt.setInt(2, msg._senderId);
		stmt.setInt(3, msg._receiverId);
		stmt.setString(4, msg._subject);
		stmt.setString(5, msg._content);
		stmt.setLong(6, msg._expiration);
		stmt.setLong(7, msg._reqAdena);
		stmt.setString(8, String.valueOf(msg._hasAttachments));
		stmt.setString(9, String.valueOf(msg._unread));
		stmt.setString(10, String.valueOf(msg._deletedBySender));
		stmt.setString(11, String.valueOf(msg._deletedByReceiver));
		stmt.setString(12, String.valueOf(msg._fourStars));
		stmt.setString(13, String.valueOf(msg._news));

		return stmt;
	}

	public final int getId()
	{
		return _messageId;
	}

	public final int getSenderId()
	{
		return _senderId;
	}

	public final int getReceiverId()
	{
		return _receiverId;
	}

	public final String getSenderName()
	{
		if (_senderName == null)
		{
			if (_fourStars)
				return "****";

			_senderName = CharNameTable.getInstance().getNameByObjectId(_senderId);
			if (_senderName == null)
				_senderName = "";
		}
		return _senderName;
	}

	public final String getReceiverName()
	{
		if (_receiverName == null)
		{
			_receiverName = CharNameTable.getInstance().getNameByObjectId(_receiverId);
			if (_receiverName == null)
				_receiverName = "";
		}
		return _receiverName;
	}

	public final String getSubject()
	{
		return _subject;
	}

	public final String getContent()
	{
		return _content;
	}

	public final boolean isLocked()
	{
		return _reqAdena > 0;
	}

	public final long getExpiration()
	{
		return _expiration;
	}

	public final int getExpirationSeconds()
	{
		return (int) (_expiration / 1000);
	}

	public final boolean isUnread()
	{
		return _unread;
	}

	public final void markAsRead()
	{
		if (_unread)
		{
			_unread = false;
			MailService.getInstance().markAsReadInDb(_messageId);
		}
	}

	public final boolean isDeletedBySender()
	{
		return _deletedBySender;
	}

	public final void setDeletedBySender()
	{
		if (!_deletedBySender)
		{
			_deletedBySender = true;
			if (_deletedByReceiver)
			{
				MailService.getInstance().deleteMessageInDb(_messageId);
			}
			else
				MailService.getInstance().markAsDeletedBySenderInDb(_messageId);
		}
	}

	public final boolean isDeletedByReceiver()
	{
		return _deletedByReceiver;
	}

	public final void setDeletedByReceiver()
	{
		if (!_deletedByReceiver)
		{
			_deletedByReceiver = true;
			if (_deletedBySender)
			{
				MailService.getInstance().deleteMessageInDb(_messageId);
			}
			else
				MailService.getInstance().markAsDeletedByReceiverInDb(_messageId);
		}
	}

	public final boolean isFourStars()
	{
		return _fourStars;
	}

	public final boolean isNews()
	{
		return _news;
	}

	public final long getReqAdena()
	{
		return _reqAdena;
	}

	public final synchronized Mail getAttachments()
	{
		if (!_hasAttachments)
			return null;

		if (_attachments == null)
		{
			_attachments = new Mail(_senderId, _messageId);
			_attachments.restore();
			_unloadTask = ThreadPoolManager.getInstance().scheduleGeneral(new AttachmentsUnloadTask(this),
					UNLOAD_ATTACHMENTS_INTERVAL + Rnd.get(UNLOAD_ATTACHMENTS_INTERVAL));
		}
		return _attachments;
	}

	public final boolean hasAttachments()
	{
		return _hasAttachments;
	}

	public final synchronized void removeAttachments()
	{
		if (_attachments != null)
		{
			_attachments = null;
			_hasAttachments = false;
			MailService.getInstance().removeAttachmentsInDb(_messageId);
			if (_unloadTask != null)
				_unloadTask.cancel(false);
		}
	}

	public final synchronized Mail createAttachments()
	{
		if (_hasAttachments || _attachments != null)
			return null;

		_attachments = new Mail(_senderId, _messageId);
		_hasAttachments = true;
		_unloadTask = ThreadPoolManager.getInstance().scheduleGeneral(new AttachmentsUnloadTask(this),
				UNLOAD_ATTACHMENTS_INTERVAL + Rnd.get(UNLOAD_ATTACHMENTS_INTERVAL));
		return _attachments;
	}

	protected final synchronized void unloadAttachments()
	{
		if (_attachments != null)
		{
			_attachments.deleteMe();
			_attachments = null;
		}
	}

	private final class AttachmentsUnloadTask implements Runnable
	{
		private Message	_msg;

		private AttachmentsUnloadTask(Message msg)
		{
			_msg = msg;
		}

		@Override
		public final void run()
		{
			if (_msg != null)
			{
				_msg.unloadAttachments();
				_msg = null;
			}
		}
	}
}
